using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;

namespace SharpSoft.Net.Protocols
{
    public class NetMessageStreamWriter : BinaryWriter
    {
        public NetMessageStreamWriter(Stream stream) : base(stream)
        {
        }
        public static Encoding DefaultEncoding = new UTF8Encoding(false);
        /// <summary>
        /// 有效的流开始字节
        /// </summary>
        public static byte[] signstart = new byte[] { (byte)'^', (byte)'^' };
        /// <summary>
        /// 有效的流结束字节
        /// </summary>
        //public static byte[] signend = new byte[] { (byte)'$', (byte)'$' };

        public override void Flush()
        {
            base.Flush();
        }

        /// <summary>
        /// 将对象写入网络流
        /// </summary>
        /// <param name="head">头对象</param>
        /// <param name="body">正文对象，正文对象将json序列化后写入网络流</param>
        public void WriteHeadAndBody(object head, object body = null)
        {
            Stream stream = null;
            if (body != null)
            {
                stream = new MemoryStream();
                var json = JsonConvert.SerializeObject(body, Formatting.None);
                var sw = new StreamWriter(stream, DefaultEncoding);
                sw.Write(json);
            }
            this.WriteHeadAndStream(head, (Stream)body);
        }
        public void WriteHeadAndStream(object head, Stream body)
        {
            NetMessage msg = new NetMessage() { Head = head, Body = body };
            this.WritNetMessagee(msg);
        }

        public void WritNetMessagee(NetMessage msg)
        {
            var headjson = JsonConvert.SerializeObject(msg.Head, Formatting.None);
            var headbytes = (msg.Encoding ?? System.Text.Encoding.UTF8).GetBytes(headjson);
            var headlength = headbytes.Length;
            var headlengthbytes = BitConverter.GetBytes(headlength);
            var bodylength = 0L;
            if (msg.Body != null)
            {
                if (msg.Body.CanSeek)
                {
                    bodylength = msg.Body.Length;
                }
                else
                {
                    throw new Exception("NetMessage's body must be canseek.");
                }

            }
            var bodylengthbytes = BitConverter.GetBytes(bodylength);
            var length = (4 + 8 + headlength + bodylength);

            BaseStream.Write(signstart, 0, signstart.Length);

            BaseStream.Write(headlengthbytes, 0, headlengthbytes.Length);
            BaseStream.Write(bodylengthbytes, 0, bodylengthbytes.Length);
            BaseStream.Write(headbytes, 0, headbytes.Length);
            if (msg.Body != null && msg.Body.CanRead)
            {
                var buf = new byte[10240];
                while (true)
                {
                    var lgh = msg.Body.Read(buf, 0, buf.Length);
                    if (lgh == 0)
                    {
                        break;
                    }
                    BaseStream.Write(buf, 0, lgh);
                }
            }
            //BaseStream.Write(signend, 0, signend.Length);

        }

        public async Task WriteNetMessageAsync(NetMessage msg)
        {
            await Task.Run(new Action(delegate { this.WritNetMessagee(msg); }));
        }
    }
}
